#[cfg(test)]
mod test {
    use std::fs::read;
    use std::process::Output;
    use std::ops::Mul;

    // mut 参数
    #[test]
    fn test_modify() {
        fn modify(mut v: Vec<u32>) -> Vec<u32> {
            v.push(42);
            v
        }

        let v = vec![1, 2, 3];
        let v = modify(v);
        println!("{:?}", v);

        let x = vec![1];
        let mut x1 = x;
        x1.push(2);
        println!("{:?}", x1);
        x1.reverse();
        println!("{:?}", x1);
    }

    // 函数参数模式匹配
    #[test]
    fn test_ref_f() {

        struct S {i: i32}

        fn f(ref _s: S) {
            println!("{:p}", _s);
        }

        let s = S{i: 12};
        f(s);
    }

    // 求两数中的最大公约数。欧几里得算法（辗转相除法）
    #[test]
    fn test_gcd() {
        fn gcd(a: u32, b: u32) -> u32 {
            if b == 0 {
                return a;
            }
            return gcd(b, a % b);
        }

        let g = gcd(60, 40);
        assert_eq!(20, g);
    }

    // 泛型函数
    #[test]
    fn test_t_square() {
        fn square<T: Mul<T, Output = T>>(x: T, y: T) -> T {
            x * y
        }

        let a: i32 = square(37, 41);
        let b: f64 = square(37.2, 41.1);
        assert_eq!(a, 1517);
        assert_eq!(b, 1528.92); // 浮点数执行结果可能有所差别

        let a = square::<u32>(37, 41);
        let b = square::<f32>(37.2, 41.1);
        assert_eq!(a, 1517);
        assert_eq!(b, 1528.9199); // 浮点数执行结果可能有所差别
    }

    // 高阶函数。函数本身作为参数
    #[test]
    fn test_high_fn() {
        fn math(op: fn(i32, i32) -> i32, a: i32, b: i32) -> i32 {
            op(a, b)
        }

        fn sum(a: i32, b: i32) -> i32 {
            a + b
        }
        fn product(a: i32, b: i32) -> i32 {
            a * b
        }

        let (a, b) = (2, 3);
        assert_eq!(math(sum, a, b), 5);
        assert_eq!(math(product, a, b), 6);
    }

    // 将函数作为返回值
    fn test_fn_return() {
        type MathOp = fn(i32, i32) -> i32;
        fn math(op: &str) -> MathOp {
            fn sum(a: i32, b: i32) -> i32 {
                a + b
            }

            fn product(a: i32, b: i32) -> i32 {
                a * b
            }

            match op {
                "sum" => sum,
                "product" => product,
                _ => {
                    println!("Warning: Not Implemented {:?} oprator, Replace with sum", op);
                    sum
                }
            }
        }
    }

    // 返回闭包
    #[test]
    fn test_closure_return() {
        fn counter(i: i32) -> Box<Fn(i32) -> i32> {
            Box::new(move |n: i32| n + i)
        }

        let f = counter(3);
        assert_eq!(4, f(1));
    }

    // 显示指定闭包类型
    #[test]
    fn test_closure_displayed() {
        let env_var = 1;
        let c: Box<Fn() -> i32> = Box::new(|| env_var + 2);
        assert_eq!(3, c());
    }

    // 复制语义类型自动实现 Fn
    #[test]
    fn test_closure_copy_type() {
        // 字符串字面量为复制语义类型
        let s = "hello";
        let c = ||{println!("{:?}", s)};

        c();
        c();
        println!("{:?}", s);
    }

    // 移动语义类型自动实现 FnOnce
    #[test]
    fn test_closure_move_type() {
        let s = "hello".to_string();
        let c = || s;
        c();
//        c(); // error: use of moved value: `c`
//        println!("{:?}", s); // error: use of moved value: `s`
    }

    // 环境变量为 复制 语义类型时 使用 move 关键字自动实现 Fn
    #[test]
    fn test_closure_move_type_copy() {
        let s = "hello";
        let c = move || {println!("{:?}", s);};
        c();
        c();
        println!("{:?}", s);
    }

    // 环境变量为 移动 语义类型时 使用 move 关键字自动实现 Fn
    #[test]
    fn test_closure_move_type_move() {
        let s = "hello".to_string();
        let c = move || {println!("{:?}", s);};
        c();
        c();
//        println!("{:?}", s);// error: use of moved value: `s`
    }

    // 修改环境变量的闭包来自动实现 FnMut
    #[test]
    fn test_closure_update_var() {
        let mut s = "rush".to_string();
        {
            let mut c = || {s += " rust"};
            c();
            c();
            // 书上说会报这个错误，但是实践并没有报错。 error: cannot borrow `s` as immutable because it is also borrowed as mutable
            println!("{:?}", s);
        }
        println!("{:?}", s);
    }

    // 自定义内部迭代器
    #[test]
    fn test_iter_in() {
        trait InIterator<T: Copy> {
            fn each<F: Fn(T) -> T>(&mut self, f: F);
        }

        impl <T: Copy> InIterator<T> for Vec<T> {
            fn each<F: Fn(T) -> T>(&mut self, f: F) {
                let mut i = 0;
                while i < self.len() {
                    self[i] = f(self[i]);
                    i += 1;
                }
            }
        }

        let mut v = vec![1, 2, 3];
        v.each(|i| i * 3);
        assert_eq!([3, 6, 9], &v[..3]);
    }

    // for 循环示例。for 循环展开后的等价代码
    #[test]
    fn test_iter_for() {
        let v = vec![1, 2, 3, 4, 5];
        for i in v {
            println!("{}", i);
        }

        // for 循环展开后的等价代码
        let v = vec![1, 2, 3, 4, 5];
        {
            let mut _iterator = v.into_iter();
            loop {
                match _iterator.next() {
                    Some(i) => println!("{}", i),
                    None => break,
                }
            }
        }
    }

    // 实现 Iterator trait 创建自定义迭代器
    #[test]
    fn test_iter_trait_impl() {
        struct Counter {
            count: usize,
        }

        impl Iterator for Counter {
            type Item = usize;
            fn next(&mut self) -> Option<usize> {
                self.count += 1;
                if self.count < 6 {
                    Some(self.count)
                }else {
                    None
                }
            }
        }

        let mut counter = Counter{count: 0};
        assert_eq!(Some(1), counter.next());
        assert_eq!(Some(2), counter.next());
        assert_eq!(Some(3), counter.next());
        assert_eq!(Some(4), counter.next());
        assert_eq!(Some(5), counter.next());
        assert_eq!(None, counter.next());
    }

    // 使用迭代器来追加字符串
    #[test]
    fn test_iter_string() {
        let mut message = "Hello".to_string();
        message.extend(&[' ', 'R', 'u', 's', 't']);
        assert_eq!("Hello Rust", &message);
    }
}